#!/bin/bash

# 证书管理系统 Docker 更新脚本
# 功能：从 production-code 仓库更新系统

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 部署根目录
DEPLOY_ROOT="/www/cert_manager"
# 源码目录  
SOURCE_DIR="$SCRIPT_DIR/source"
# 备份目录
BACKUP_DIR="$DEPLOY_ROOT/backup/update"

# 生产代码仓库
PRODUCTION_REPO_GITEE="https://gitee.com/zhuxbo/production-code.git"
PRODUCTION_REPO_GITHUB="https://github.com/zhuxbo/production-code.git"

# 解析命令行参数
FORCE_REPO=""
UPDATE_MODULE=""
for arg in "$@"; do
    case $arg in
        gitee)
            FORCE_REPO="gitee"
            log_info "强制使用 Gitee 仓库"
            ;;
        github)
            FORCE_REPO="github"
            log_info "强制使用 GitHub 仓库"
            ;;
        api|backend)
            UPDATE_MODULE="backend"
            log_info "仅更新后端"
            ;;
        admin|user|easy)
            UPDATE_MODULE="$arg"
            log_info "仅更新前端: $arg"
            ;;
        nginx)
            UPDATE_MODULE="nginx"
            log_info "仅更新 Nginx 配置"
            ;;
        -h|help)
            echo "用法: $0 [选项] [模块]"
            echo "选项:"
            echo "  gitee   - 强制使用 Gitee 仓库"
            echo "  github  - 强制使用 GitHub 仓库"
            echo "模块:"
            echo "  api/backend - 仅更新后端"
            echo "  admin      - 仅更新管理端"
            echo "  user       - 仅更新用户端"
            echo "  easy       - 仅更新简易端"
            echo "  nginx      - 仅更新 Nginx 配置"
            echo "  (不指定模块则更新所有)"
            exit 0
            ;;
    esac
done

# 拉取最新代码
pull_latest_code() {
    log_info "获取最新生产代码..."
    
    cd "$SOURCE_DIR"
    
    if [ ! -d "production-code" ]; then
        log_error "生产代码目录不存在，请先运行 install.sh"
        exit 1
    fi
    
    cd production-code
    
    # 保存当前版本
    OLD_VERSION=""
    if [ -f "config.json" ]; then
        if command -v jq >/dev/null 2>&1; then
            OLD_VERSION=$(jq -r '.version' config.json 2>/dev/null || true)
        else
            OLD_VERSION=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"\n]*\)".*/\1/p' config.json | head -n1)
        fi
    fi
    
    # 如果指定了强制仓库，先切换
    if [ -n "$FORCE_REPO" ]; then
        if [ "$FORCE_REPO" = "gitee" ]; then
            log_info "切换到 Gitee 仓库..."
            git remote set-url origin "$PRODUCTION_REPO_GITEE"
        elif [ "$FORCE_REPO" = "github" ]; then
            log_info "切换到 GitHub 仓库..."
            git remote set-url origin "$PRODUCTION_REPO_GITHUB"
        fi
    fi
    
    # 尝试拉取更新
    if ! git fetch origin >/dev/null 2>&1; then
        if [ -n "$FORCE_REPO" ]; then
            log_error "无法从指定的 $FORCE_REPO 仓库拉取代码"
            exit 1
        fi
        
        log_warning "从当前仓库拉取失败，尝试切换仓库..."
        local current_url=$(git remote get-url origin 2>/dev/null || echo "")
        
        if [[ "$current_url" == *"gitee.com"* ]]; then
            log_info "切换到 GitHub 仓库..."
            git remote set-url origin "$PRODUCTION_REPO_GITHUB"
        else
            log_info "切换到 Gitee 仓库..."
            git remote set-url origin "$PRODUCTION_REPO_GITEE"
        fi
        
        if ! git fetch origin >/dev/null 2>&1; then
            log_error "无法从任何仓库拉取代码"
            exit 1
        fi
    fi
    
    git reset --hard origin/main >/dev/null 2>&1
    
    # 获取新版本
    NEW_VERSION=""
    if [ -f "config.json" ]; then
        if command -v jq >/dev/null 2>&1; then
            NEW_VERSION=$(jq -r '.version' config.json 2>/dev/null || true)
        else
            NEW_VERSION=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"\n]*\)".*/\1/p' config.json | head -n1)
        fi
    fi
    
    if [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
        log_info "当前已是最新版本: $NEW_VERSION"
    else
        log_success "版本更新: $OLD_VERSION -> $NEW_VERSION"
    fi
    
    cd "$SCRIPT_DIR"
}

# 备份当前版本
backup_current() {
    BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    BACKUP_PATH="$BACKUP_DIR/update_$BACKUP_TIMESTAMP"
    
    log_info "备份当前版本..."
    mkdir -p "$BACKUP_PATH"
    
    # 根据更新模块选择备份内容
    if [ -z "$UPDATE_MODULE" ]; then
        # 全量备份
        for dir in backend frontend nginx; do
            if [ -d "$DEPLOY_ROOT/$dir" ]; then
                cp -r "$DEPLOY_ROOT/$dir" "$BACKUP_PATH/" 2>/dev/null
            fi
        done
    elif [ "$UPDATE_MODULE" = "backend" ]; then
        # 仅备份后端
        if [ -d "$DEPLOY_ROOT/backend" ]; then
            cp -r "$DEPLOY_ROOT/backend" "$BACKUP_PATH/" 2>/dev/null
        fi
    elif [ "$UPDATE_MODULE" = "nginx" ]; then
        # 仅备份 nginx
        if [ -d "$DEPLOY_ROOT/nginx" ]; then
            cp -r "$DEPLOY_ROOT/nginx" "$BACKUP_PATH/" 2>/dev/null
        fi
    else
        # 备份指定的前端模块
        if [ -d "$DEPLOY_ROOT/frontend/$UPDATE_MODULE" ]; then
            mkdir -p "$BACKUP_PATH/frontend"
            cp -r "$DEPLOY_ROOT/frontend/$UPDATE_MODULE" "$BACKUP_PATH/frontend/" 2>/dev/null
        fi
    fi
    
    # 备份配置文件
    if [ -f "$DEPLOY_ROOT/config.json" ]; then
        cp "$DEPLOY_ROOT/config.json" "$BACKUP_PATH/"
    fi
    
    # 创建备份信息
    cat > "$BACKUP_PATH/backup_info.txt" <<EOF
备份时间: $(date)
备份原因: 系统更新
更新模块: ${UPDATE_MODULE:-全部}
旧版本: $OLD_VERSION
新版本: $NEW_VERSION

恢复方法:
1. 停止服务: docker compose down
2. 恢复文件: cp -r $BACKUP_PATH/* $DEPLOY_ROOT/
3. 重启服务: docker compose up -d
EOF
    
    log_success "备份完成: $BACKUP_PATH"
}

# 保存重要文件
save_important_files() {
    log_info "保存重要配置文件..."
    
    # 创建临时目录
    TEMP_SAVE="/tmp/cert_update_$$"
    mkdir -p "$TEMP_SAVE"
    
    # 保存 .env 文件
    if [ -f "$DEPLOY_ROOT/backend/.env" ]; then
        cp "$DEPLOY_ROOT/backend/.env" "$TEMP_SAVE/"
    fi
    
    # 保存上传的文件
    if [ -d "$DEPLOY_ROOT/backend/storage/app/public" ]; then
        cp -r "$DEPLOY_ROOT/backend/storage/app/public" "$TEMP_SAVE/" 2>/dev/null
    fi
    
    # 保存日志
    if [ -d "$DEPLOY_ROOT/backend/storage/logs" ]; then
        cp -r "$DEPLOY_ROOT/backend/storage/logs" "$TEMP_SAVE/" 2>/dev/null
    fi
    
    # 保存前端配置（web 目录永远保持不变，不需要保存）
    for config_file in "$DEPLOY_ROOT/frontend/admin/platform-config.json" \
                      "$DEPLOY_ROOT/frontend/user/platform-config.json" \
                      "$DEPLOY_ROOT/frontend/easy/config.json"; do
        if [ -f "$config_file" ]; then
            local filename=$(basename "$config_file")
            local dirname=$(basename $(dirname "$config_file"))
            mkdir -p "$TEMP_SAVE/$dirname"
            cp "$config_file" "$TEMP_SAVE/$dirname/"
        fi
    done
}

# 恢复重要文件
restore_important_files() {
    log_info "恢复重要配置文件..."
    
    if [ -d "$TEMP_SAVE" ]; then
        # 恢复 .env
        if [ -f "$TEMP_SAVE/.env" ]; then
            cp "$TEMP_SAVE/.env" "$DEPLOY_ROOT/backend/"
        fi
        
        # 恢复上传文件
        if [ -d "$TEMP_SAVE/public" ]; then
            cp -r "$TEMP_SAVE/public" "$DEPLOY_ROOT/backend/storage/app/" 2>/dev/null
        fi
        
        # 恢复日志
        if [ -d "$TEMP_SAVE/logs" ]; then
            cp -r "$TEMP_SAVE/logs" "$DEPLOY_ROOT/backend/storage/" 2>/dev/null
        fi
        
        # 恢复前端配置（web 目录永远保持不变，不需要恢复）
        for dir in admin user easy; do
            if [ -d "$TEMP_SAVE/$dir" ]; then
                cp -r "$TEMP_SAVE/$dir"/* "$DEPLOY_ROOT/frontend/$dir/" 2>/dev/null
            fi
        done
        
        # 清理临时目录
        rm -rf "$TEMP_SAVE"
    fi
}

# 更新文件
update_files() {
    log_info "更新系统文件..."
    
    SOURCE_PATH="$SOURCE_DIR/production-code"
    
    if [ -z "$UPDATE_MODULE" ]; then
        # 全量更新
        log_info "执行全量更新..."
        
        # 保存重要文件
        save_important_files
        
        # 清理并复制新文件（保留 web 目录）
        rm -rf "$DEPLOY_ROOT/backend" "$DEPLOY_ROOT/nginx"
        
        # 只删除和更新特定的前端目录，保留 web 目录
        for component in admin user easy; do
            [ -d "$DEPLOY_ROOT/frontend/$component" ] && rm -rf "$DEPLOY_ROOT/frontend/$component"
        done
        
        cp -r "$SOURCE_PATH/backend" "$DEPLOY_ROOT/" 2>/dev/null
        cp -r "$SOURCE_PATH/nginx" "$DEPLOY_ROOT/" 2>/dev/null
        
        # 复制前端文件（排除 web 目录）
        for component in admin user easy; do
            if [ -d "$SOURCE_PATH/frontend/$component" ]; then
                mkdir -p "$DEPLOY_ROOT/frontend"
                cp -r "$SOURCE_PATH/frontend/$component" "$DEPLOY_ROOT/frontend/" 2>/dev/null
            fi
        done
        
        # 恢复重要文件
        restore_important_files
        
    elif [ "$UPDATE_MODULE" = "backend" ]; then
        # 仅更新后端
        log_info "更新后端..."
        
        # 保存重要文件
        save_important_files
        
        # 更新后端代码
        rm -rf "$DEPLOY_ROOT/backend"
        cp -r "$SOURCE_PATH/backend" "$DEPLOY_ROOT/" 2>/dev/null
        
        # 恢复重要文件
        restore_important_files
        
    elif [ "$UPDATE_MODULE" = "nginx" ]; then
        # 仅更新 nginx
        log_info "更新 Nginx 配置..."
        rm -rf "$DEPLOY_ROOT/nginx"
        cp -r "$SOURCE_PATH/nginx" "$DEPLOY_ROOT/" 2>/dev/null
        
    else
        # 更新指定的前端模块
        log_info "更新前端模块: $UPDATE_MODULE..."
        
        # 保存配置文件
        if [ "$UPDATE_MODULE" = "admin" ] || [ "$UPDATE_MODULE" = "user" ]; then
            if [ -f "$DEPLOY_ROOT/frontend/$UPDATE_MODULE/platform-config.json" ]; then
                cp "$DEPLOY_ROOT/frontend/$UPDATE_MODULE/platform-config.json" "/tmp/platform-config-$UPDATE_MODULE.json"
            fi
        elif [ "$UPDATE_MODULE" = "easy" ]; then
            if [ -f "$DEPLOY_ROOT/frontend/easy/config.json" ]; then
                cp "$DEPLOY_ROOT/frontend/easy/config.json" "/tmp/easy-config.json"
            fi
        fi
        
        # 更新文件
        rm -rf "$DEPLOY_ROOT/frontend/$UPDATE_MODULE"
        cp -r "$SOURCE_PATH/frontend/$UPDATE_MODULE" "$DEPLOY_ROOT/frontend/" 2>/dev/null
        
        # 恢复配置文件
        if [ "$UPDATE_MODULE" = "admin" ] || [ "$UPDATE_MODULE" = "user" ]; then
            if [ -f "/tmp/platform-config-$UPDATE_MODULE.json" ]; then
                cp "/tmp/platform-config-$UPDATE_MODULE.json" "$DEPLOY_ROOT/frontend/$UPDATE_MODULE/platform-config.json"
                rm "/tmp/platform-config-$UPDATE_MODULE.json"
            fi
        elif [ "$UPDATE_MODULE" = "easy" ]; then
            if [ -f "/tmp/easy-config.json" ]; then
                cp "/tmp/easy-config.json" "$DEPLOY_ROOT/frontend/easy/config.json"
                rm "/tmp/easy-config.json"
            fi
        fi
    fi
    
    # 更新版本文件
    if [ -f "$SOURCE_PATH/config.json" ]; then
        cp "$SOURCE_PATH/config.json" "$DEPLOY_ROOT/"
    fi
    
    log_success "文件更新完成"
}

# 更新后处理
post_update() {
    log_info "执行更新后处理..."
    
    # 如果更新了后端，执行 Laravel 相关操作
    if [ -z "$UPDATE_MODULE" ] || [ "$UPDATE_MODULE" = "backend" ]; then
        log_info "清理 Laravel 缓存..."
        
        docker exec cert-php sh -c "
            cd /www/cert_manager/backend &&
            php artisan cache:clear &&
            php artisan config:clear &&
            php artisan route:clear &&
            php artisan view:clear &&
            php artisan migrate --force
        " 2>/dev/null || log_warning "Laravel 缓存清理可能需要手动完成"
        
        # 重启 PHP 容器
        log_info "重启 PHP 服务..."
        docker restart cert-php cert-queue cert-scheduler
    fi
    
    # 如果更新了 nginx 配置，重启 nginx
    if [ -z "$UPDATE_MODULE" ] || [ "$UPDATE_MODULE" = "nginx" ]; then
        log_info "重启 Nginx 服务..."
        docker restart cert-nginx
    fi
    
    log_success "更新后处理完成"
}

# 清理旧备份
cleanup_old_backups() {
    log_info "清理旧备份..."
    
    # 保留最近10个备份
    if [ -d "$BACKUP_DIR" ]; then
        cd "$BACKUP_DIR"
        ls -dt update_* 2>/dev/null | tail -n +11 | xargs -r rm -rf
    fi
    
    log_success "旧备份清理完成"
}

# 主函数
main() {
    log_info "证书管理系统 Docker 更新"
    echo
    
    # 检查部署目录
    if [ ! -d "$DEPLOY_ROOT" ]; then
        log_error "系统未安装，请先运行 install.sh"
        exit 1
    fi
    
    # 拉取最新代码
    echo
    pull_latest_code
    
    # 备份当前版本
    echo
    backup_current
    
    # 更新文件
    echo
    update_files
    
    # 更新后处理
    echo
    post_update
    
    # 清理旧备份
    echo
    cleanup_old_backups
    
    echo
    log_success "=================================================="
    log_success " 系统更新完成！"
    log_success "=================================================="
    echo
    log_info "新版本: $NEW_VERSION"
    log_info "备份位置: $BACKUP_PATH"
    echo
    log_info "如遇问题，可使用以下命令恢复："
    log_info "  1. docker compose down"
    log_info "  2. cp -r $BACKUP_PATH/* $DEPLOY_ROOT/"
    log_info "  3. docker compose up -d"
    echo
}

# 执行主函数
main "$@"